
#include "SdlTracer.hpp"
#include "Math.hpp"
#include <SDL.h>
#include <unistd.h>
#include <iostream>
#include <sstream>

using namespace com::toxiclabs::tsoc::sdl;
using namespace std;

bool global_quit_request=false;

void * sdl_thread_func(void * data)
{
	static int id = -1;
	com::toxiclabs::tsoc::RayTracer * rt;
	SDL_Event event;
	
	id++;
	rt = (com::toxiclabs::tsoc::RayTracer *)data;
	
	
	rt->Render();
	
	int t[4];
	
	for(int n=0;n<1024;n++)
	{
			t[0]=SDL_GetTicks();
			rt->Irradiate();
			t[1]=SDL_GetTicks();
			rt->Compose();
			t[2]=SDL_GetTicks();
		
		
			cout<<"Irradiate time: "<<(t[1]-t[0])<<endl;
			cout<<"Compose time:"<<(t[2]-t[1])<<endl;
			
		
			//once render is already done, we send a death notification
			event.type=SDL_USEREVENT;
			event.user.code=2;
			SDL_PushEvent(&event);

			stringstream ss;
			ss<<"/tmp/out-"<<n<<".tga";
			rt->TGADump(ss.str().c_str());
			
			if(global_quit_request)break;		
	}
	
	
}

SDLTracer::SDLTracer(int width,int height,int threads, Scene * scene,Graph * graph) : RayTracer(width,height,threads,scene,graph)
{
	
	 SDL_Init(SDL_INIT_VIDEO);
     
     /* Initialize the screen / window */
     screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE);
}


SDLTracer::~SDLTracer()
{
	
	SDL_Quit();
}


void SDLTracer::CommitChunk(Chunk * chunk)
{
	
	SDL_Event event;
	
	event.type=SDL_USEREVENT;
	event.user.code=1;
	event.user.data1=chunk;
	
	//as read on docs, this function should be thread safe
	SDL_PushEvent(&event);
}


void SDLTracer::Run()
{
	pthread_t thread;
	
	cout<<"SDL Rendering with "<<num_threads<<" threads"<<endl;
	
	pthread_create(&thread,NULL,sdl_thread_func,this);
	
	
	SDL_Event event;
	bool quit_request=false;
	bool compose_ready=false;
	Chunk * chunk = NULL;
	
	while(!quit_request)
	{
		compose_ready=false;
		while(SDL_PollEvent(&event))
		{
			if(event.type==SDL_MOUSEBUTTONDOWN)
			{
				HitPoint * hit = hits[event.button.x+event.button.y*width];
				cout<<"HitPoint ("<<event.button.x<<","<<event.button.y<<"):"<<endl;
				cout<<"flux:"<<hit->flux[0]<<","<<hit->flux[1]<<","<<hit->flux[2]<<endl;
			}
			
			if (event.type==SDL_KEYDOWN)
			{
				if (event.key.keysym.sym == SDLK_ESCAPE)
				{
					quit_request=true;
					global_quit_request=true;
				}
			}
	
			if (event.type==SDL_USEREVENT)
			{
				switch(event.user.code)
				{
					//commit chunk
					case 1:
							chunk = (Chunk *)event.user.data1;
							DrawChunk(chunk);
							//cout<<"* commit chunk ("<<chunk->x<<","<<chunk->y<<")"<<endl;
							delete chunk;
					break;
					
					//thread is done
					case 2:
						compose_ready=true;
					break;
				}
			}
			
			
		}
	}
	
	pthread_join(thread,NULL);
	
	cout<<"completed!"<<endl;
	
	
}


void SDLTracer::DrawChunk(Chunk * chunk)
{
	uint32_t value;
	
	for(int j=chunk->y;j<(chunk->y+chunk->h);j++)
	{
		for(int i=chunk->x;i<(chunk->x+chunk->w);i++)
		{
			value = buffer[i+j*width];
			((uint32_t *)(screen->pixels))[i+j*width] = SDL_MapRGB(screen->format,(value & 0xFF000000)>>24,(value & 0x00FF0000)>>16,(value & 0x0000FF00)>>8);
		}
	}

	SDL_UpdateRect(screen,chunk->x,chunk->y,chunk->w,chunk->h);
}

/*
void SDLTracer::Wait()
{
	SDL_Event event;
	bool quit_request=false;
	
	while(!quit_request)
	{
		while(SDL_PollEvent(&event))
		{
			if (event.type==SDL_KEYDOWN)
			{
				if (event.key.keysym.sym == SDLK_ESCAPE)quit_request=true;
			}
			
			if(event.type==SDL_QUIT)
				quit_request=true;
				
			if(event.type==SDL_MOUSEBUTTONDOWN)
			{
				int x=event.button.x;
				int y=event.button.y;
				cout<<"Position: "<<x<<","<<y<<endl;
				cout<<"\tcolor:"<<hex<<buffer[x+y*width]<<endl;
				cout<<"\tdepth:"<<dec<<zbuffer[x+y*width]<<endl;
			}
		}
		
		usleep(250000);
	}
	
}
*/
